package org.asiainfo.flowable.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.utils.SpringUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.flowable.utils.ModelUtils;
import org.asiainfo.common.mybatis.stream.core.page.TableDataInfo;
import org.asiainfo.common.mybatis.stream.core.page.PageQuery;
import org.asiainfo.flowable.domain.WfForm;
import org.asiainfo.flowable.domain.table.WfDeployFormTableDef;
import org.asiainfo.flowable.domain.table.WfFormTableDef;
import org.asiainfo.flowable.domain.vo.WfDeployFormVo;
import org.asiainfo.flowable.domain.bo.WfDeployFormBo;
import org.asiainfo.flowable.domain.WfDeployForm;
import org.asiainfo.flowable.domain.vo.WfFormVo;
import org.asiainfo.flowable.service.WfDeployFormService;
import org.asiainfo.flowable.service.WfFormService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.bpmn.model.UserTask;
import org.springframework.stereotype.Service;
import org.asiainfo.common.core.utils.MapstructUtils;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.asiainfo.flowable.mapper.WfDeployFormMapper;
import com.mybatisflex.core.paginate.Page;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Map;
import java.util.Collection;
import java.util.List;

/**
 * 流程实例关联表单(WfDeployForm)表服务实现类
 *
 * @author dotor-ww
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class WfDeployFormServiceImpl extends ServiceImpl<WfDeployFormMapper, WfDeployForm> implements WfDeployFormService {

    /**
     * 查询
     *
     * @param wfDeployFormBo 筛选条件
     * @return 查询结果
     */
    @Override
    public List<WfDeployFormVo> queryList(WfDeployFormBo wfDeployFormBo) {
        Map<String, Object> params = wfDeployFormBo.getParams();
        QueryWrapper query = query();
        return listAs(query, WfDeployFormVo.class);
    }

    /**
     * 通过deployId查询单条数据
     *
     * @param deployId 主键
     * @return 实例对象
     */
    @Override
    public WfDeployFormVo queryById(String deployId) {
        return getOneAs(query().eq(WfDeployForm::getDeployId, deployId), WfDeployFormVo.class);
    }

    /**
     * 分页查询
     *
     * @param wfDeployFormBo 筛选条件
     * @param pageQuery      分页对象
     * @return 查询结果
     */
    @Override
    public TableDataInfo<WfDeployFormVo> queryPageList(WfDeployFormBo wfDeployFormBo, PageQuery pageQuery) {
        Map<String, Object> params = wfDeployFormBo.getParams();
        QueryWrapper query = query().between(WfDeployForm::getCreateTime, params.get("beginTime"), params.get("endTime"),
                ObjectUtil.isNotNull(params.get("beginTime")) && ObjectUtil.isNotNull(params.get("endTime")));
        pageQuery.buildOrder(query);
        Page<WfDeployFormVo> page = pageAs(pageQuery.buildPage(), query, WfDeployFormVo.class);
        return TableDataInfo.build(page);
    }

    /**
     * 新增数据
     *
     * @param wfDeployFormBo 实例对象
     * @return 实例对象
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertByBo(WfDeployFormBo wfDeployFormBo) {
        // 删除部署流程和表单关联关系
        remove(query().eq(WfDeployForm::getDeployId, wfDeployFormBo.getDeployId()));
        WfDeployForm wfDeployForm = MapstructUtils.convert(wfDeployFormBo, WfDeployForm.class);
        // 新增部署流程和表单关系
        return save(wfDeployForm);
    }

    /**
     * 修改数据
     *
     * @param wfDeployFormBo 实例对象
     * @return 实例对象
     */
    @Override
    public Boolean updateByBo(WfDeployFormBo wfDeployFormBo) {
        WfDeployForm wfDeployForm = MapstructUtils.convert(wfDeployFormBo, WfDeployForm.class);
        return updateById(wfDeployForm);
    }

    /**
     * 通过主键删除数据
     *
     * @param deployIds 主键
     * @return 是否成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> deployIds) {
        return removeByIds(deployIds);
    }

    /**
     * 查询流程部署关联表单信息
     *
     * @param deployId 流程部署ID
     * @return 流程部署关联表单信息
     */
    @Override
    public WfFormVo queryFormByDeployId(String deployId) {
        List<WfFormVo> wfFormVos = queryChain()
            .select(WfFormTableDef.WF_FORM.FORM_ID, WfFormTableDef.WF_FORM.FORM_NAME, WfFormTableDef.WF_FORM.RULE, WfFormTableDef.WF_FORM.OPTIONS)
            .from(WfForm.class)
            .leftJoin(WfDeployForm.class)
            .on(WfFormTableDef.WF_FORM.FORM_ID.eq(WfFormTableDef.WF_FORM.FORM_ID))
            .where(WfDeployFormTableDef.WF_DEPLOY_FORM.DEPLOY_ID.eq(deployId))
            .listAs(WfFormVo.class);

        if (CollUtil.isNotEmpty(wfFormVos)) {
            if (wfFormVos.size() != 1) {
                throw new ServiceException("流程部署关联表单信息异常");
            }
            return wfFormVos.get(0);
        }
        return null;
    }

    /**
     * 保存流程实例关联表单
     *
     * @param deployId  流程部署ID
     * @param bpmnModel 流程模型
     * @return 保存结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel) {
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        if (ObjectUtil.isNull(startEvent)) {
            throw new ServiceException("流程模型异常，未找到开始节点");
        }
        WfDeployForm startWfDeployForm = buildDeployForm(deployId, startEvent);
        List<WfDeployForm> deployForms = new ArrayList<>();
        if (ObjectUtil.isNotNull(startWfDeployForm)) {
            deployForms.add(startWfDeployForm);
        }
        Collection<UserTask> userTasks = ModelUtils.getAllUserTaskEvent(bpmnModel);
        for (UserTask userTask : userTasks) {
            WfDeployForm userTaskDeployForm = buildDeployForm(deployId, userTask);
            if (ObjectUtil.isNotNull(userTaskDeployForm)) {
                deployForms.add(userTaskDeployForm);
            }
        }
        return saveBatch(deployForms);
    }

    /**
     * 构建部署表单关联信息对象
     *
     * @param deployId 部署ID
     * @param node     节点信息
     * @return 部署表单关联对象。若无表单信息（formKey），则返回null
     */
    private WfDeployForm buildDeployForm(String deployId, FlowNode node) {
        String formKey = ModelUtils.getFormKey(node);
        if (StringUtils.isEmpty(formKey)) {
            return null;
        }
        Long formId = Convert.toLong(StringUtils.substringAfter(formKey, "key_"));
        WfFormVo wfFormVo = SpringUtils.getBean(WfFormService.class).queryById(formId);
        if (ObjectUtil.isNull(wfFormVo)) {
            throw new ServiceException("表单信息查询错误");
        }
        WfDeployForm deployForm = new WfDeployForm();
        deployForm.setDeployId(deployId);
        deployForm.setFormKey(formKey);
        deployForm.setNodeKey(node.getId());
        deployForm.setFormName(wfFormVo.getFormName());
        deployForm.setNodeName(node.getName());
        deployForm.setRule(wfFormVo.getRule());
        deployForm.setOption(wfFormVo.getOptions());
        return deployForm;
    }
}
